// TestSpecService.cpp : Defines the entry point for the console application.
//
#include "Infra/Messaging/Message.h"
#include "Infra/Messaging/Channel.h"
#include "Infra/Messaging/SynchronousMsg.h"
#include "Spot/Domain/MarketData.h"
#include "Spot/Messages/MarketDataMsg.h"

#include <boost/test/auto_unit_test.hpp>

#include <iostream>

void test_sleep( double secs );

class MockMarketDataSubscriber : public Spot::Arrow::IMarketDataRecipient
{
public:
	MockMarketDataSubscriber( void ) : i( 0 ) {}

	void processMarketData( const Spot::Domain::UnderlyingQuote& quote )
	{
		::test_sleep( .025 );
	}
	void processMarketData( const Spot::Domain::CompositeOptionQuote& quote )
	{
		::test_sleep( .025 );
	}
	void processMarketData( const Spot::Domain::StockTrade& trade )
	{
		::test_sleep( .050 );
	}
	void processMarketData( const Spot::Domain::OptionTrade& trade )
	{
		::test_sleep( .050 );
	}
	int i;
};

BOOST_AUTO_TEST_CASE(SubscribeToQuotes)
{
	::printf("SubscribeToQuotes\n");

	Spot::Domain::StockQuoteInfo sq1;
	sq1.symbol = "A  HY";
	sq1.sequence = 0;
	sq1.timestamp = ::time( 0 );
	sq1.bid.exchange = 'C';
	sq1.ask.exchange = 'C';
	sq1.bid.price = 33.90;
	sq1.ask.price = 33.95;
	sq1.ask.size = 100;
	sq1.bid.size = 100;

	Spot::Domain::OptionQuoteInfo oq1;
	oq1.symbol = "A  HY";
	oq1.sequence = 1;
	oq1.timestamp = ::time( 0 );
	oq1.bid.exchange = 'C';
	oq1.ask.exchange = 'C';
	oq1.bid.price = 3.70;
	oq1.ask.price = 3.90;
	oq1.bid.size = 230;
	oq1.ask.size = 236;

	Spot::Domain::OptionQuoteInfo oq2;
	oq2.symbol = "A  HY";
	oq2.sequence = 2;
	oq2.timestamp = ::time( 0 );
	oq2.bid.exchange = 'C';
	oq2.ask.exchange = 'C';
	oq2.bid.price = 3.50;
	oq2.ask.price = 3.60;
	oq2.bid.size = 230;
	oq2.ask.size = 236;

	Spot::Domain::StockQuoteInfo sq2;
	sq2.symbol = "A  HY";
	sq2.sequence = 3;
	sq2.timestamp = ::time( 0 );
	sq2.bid.exchange = 'C';
	sq2.ask.exchange = 'C';
	sq2.bid.price = 34.40;
	sq2.ask.price = 34.60;
	sq2.bid.size = 200;
	sq2.ask.size = 200;

	Spot::Domain::OptionQuoteInfo oq3;
	oq3.symbol = "A  HY";
	oq3.sequence = 5;
	oq3.timestamp = ::time( 0 );
	oq3.bid.exchange = 'C';
	oq3.ask.exchange = 'C';
	oq3.bid.price = 6.50;
	oq3.ask.price = 6.60;
	oq3.bid.size = 69;
	oq3.ask.size = 236;

	Infra::Messaging::Channel channel;

	Infra::Messaging::Publication& waitPub = channel.publish< Infra::Messaging::SynchronousMsg >();
	Infra::Messaging::Publication& sqPub = channel.publish< Spot::Arrow::UnderlyingQuoteMsg >( "SQ" );
	Infra::Messaging::Publication& oqPub = channel.publish< Spot::Arrow::CompositeOptionQuoteMsg >( "OQ" );

	MockMarketDataSubscriber subscriber;

	Infra::Messaging::Subscription sub1 = channel.makeSubscription( &subscriber, "SQ", "A  HY" );
	sub1.activate();
	Infra::Messaging::Subscription sub2 = channel.makeSubscription( &subscriber, "OQ", "A  HY" );
	sub2.activate();

	// Resets all stats including subscription stats
	channel.start();

	for ( int i = 0; i < 100000; ++i )
	{
		Spot::Arrow::UnderlyingQuoteMsg msg1( sqPub.getTopic( sq1.symbol ), sq1 );
		channel.onMessage( msg1 );
		Spot::Arrow::CompositeOptionQuoteMsg msg2( oqPub.getTopic( oq1.symbol ), oq1 );
		channel.onMessage( msg2 );
		Spot::Arrow::CompositeOptionQuoteMsg msg3( oqPub.getTopic( oq2.symbol ), oq2 );
		channel.onMessage( msg3 );
		Spot::Arrow::UnderlyingQuoteMsg msg4( sqPub.getTopic( sq2.symbol ), sq2 );
		channel.onMessage( msg4 );
		Spot::Arrow::CompositeOptionQuoteMsg ms5( oqPub.getTopic( oq3.symbol ), oq3 );
		channel.onMessage( ms5 );
	}

	Infra::Messaging::SynchronousMsg synchMessage( waitPub.getTopic() );
	channel.onMessage( synchMessage );
	synchMessage.wait();

	channel.stop();

	channel.printStats( std::cout );
}